/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_httpd.htm
 *
 * Zhiqim Httpd is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.httpd.context.service;

import java.io.IOException;

import org.zhiqim.httpd.HttpConnection;
import org.zhiqim.httpd.HttpExecutor;
import org.zhiqim.httpd.HttpRequest;
import org.zhiqim.httpd.HttpRequestAbs;
import org.zhiqim.httpd.HttpResponse;
import org.zhiqim.httpd.HttpSession;
import org.zhiqim.httpd.context.ZmlContextConstants;
import org.zhiqim.httpd.websocket.HttpWebSocketService;
import org.zhiqim.kernel.model.codes.Base64;
import org.zhiqim.kernel.model.codes.SHA1;

/**
 * HttpWebsocket服务
 *
 * @version v1.0.0 @author zouzhigang 2017-6-9 新建与整理
 */
public class WebSocketService implements HttpExecutor, ZmlContextConstants
{
    @Override
    public boolean isMatch(String pathInContext)
    {
        return _PATH_SERVICE_WS_.equals(pathInContext);
    }

    @Override
    public void handle(HttpRequest request, HttpResponse response) throws IOException
    {
        if (!request.isWebSocket())
        {//非WS服务不支持
            response.sendError(_405_METHOD_NOT_ALLOWD_);
            return;
        }
        
        HttpSession session = request.getSession();
        if (session == null)
        {//必须会话支持
            response.sendError(_403_FORBIDDEN_);
            return;
        }
        
        String protocol = request.getHeader(_SEC_WEBSOCKET_PROTOCOL_, null);
        HttpWebSocketService service = request.getContext().getWebSocketManager().getWebSocketService(protocol);
        if (service == null)
        {//服务端没有配置WebSocket
            response.sendError(_406_NOT_ACCEPTABLE_);
            return;
        }
        
        //1.响应成功
        response.setStatus(_101_SWITCHING_PROTOCOLS_);
        response.setHeader(_CONNECTION_, _UPGRADE_);
        response.setHeader(_UPGRADE_, _WEBSOCKET_);
        
        //2.响应Sec-WebSocket-Accept&Sec-WebSocket-Protocol
        String key = request.getHeader(_SEC_WEBSOCKET_KEY_);
        String accept = Base64.encode(SHA1.encodeByte(key + _WEBSOCKET_SALT_, _UTF_8_C_));
        response.setHeader(_SEC_WEBSOCKET_ACCEPT_, accept);
        
        if (protocol != null)
        {//响应协议
            response.setHeader(_SEC_WEBSOCKET_PROTOCOL_, protocol);
        }
        
        //3.升级连接为WS连接
        HttpConnection conn = ((HttpRequestAbs)request).getConnection();
        conn.doWebSocket(request.getContext(), request.getHeaderMap(), request.getParameterMap(), protocol, session.getId(), service);
    }
}
